home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / CH_4.1 / CELLOG / CELLOG.C < prev    next >
C/C++ Source or Header  |  1999-09-11  |  10KB  |  312 lines

  1. /* 
  2.  * cellog.c
  3.  * 
  4.  * Practical Algorithms for Image Analysis
  5.  * 
  6.  * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
  7.  */
  8.  
  9. /* CELLOG:      program performs cellular logic based on crossing number and
  10.  *    factor number
  11.  *              usage: cellog inimg outimg [-f FAC_THRESH] [-c CONNECTIVITY]
  12.  *                                         [-i ITERATIONS] [-o OPERATION] [-I] [-L]
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include "tiffimage.h"          /* picfile info on images */
  19. #include "images.h"
  20. extern void print_sos_lic ();
  21.  
  22. #define ON 255                  /* binarization values */
  23. #define OFF 0
  24. #define FAC_THRESH_DFLT 5       /* default threshold on factor number */
  25. #define NITER_DFLT 1            /* default threshold on number iteratoins */
  26.  
  27. long crossnum (long *, long);
  28. int usage (short);
  29. int input (int, char **, long *, short *, long *, long *, long *);
  30.  
  31. main (argc, argv)
  32.      int argc;
  33.      char *argv[];
  34.  
  35. {
  36.   Image *imgI, *imgO;           /* input and output image structures */
  37.   unsigned char **imgIn, **imgOut;  /* input and output image arrays */
  38.   long width, height;           /* size of image */
  39.   long facThresh;               /* factor number threshold */
  40.   short connectFlag;            /* =1 to retain connectivity; 0 otherwise */
  41.   long nIter;                   /* number of iterations to perform */
  42.   long opType;                  /* operation type */
  43.   long invertFlag;              /* invert input image before processing */
  44.   long xEnd, yEnd;              /* end of image within 1-pixel borders */
  45.   long ring[8];                 /* neighborhood ring, top=ring[0] */
  46.   long fNum, cNum;              /* factor number and crossing number */
  47.   long nChange;                 /* number pixels changed on iteration */
  48.   long x, y, i, n;
  49.  
  50. /* user input */
  51.   if ((input (argc, argv, &facThresh, &connectFlag, &nIter, &opType, &invertFlag)) < 0)
  52.     return (-1);
  53.  
  54. /* factor number has greater effect for larger number; number entered by
  55.  * user is for dilation, so for erosion, invert threshold value */
  56.   if (opType == 2 || opType == 4)
  57.     facThresh = 7 - facThresh;
  58.  
  59. /* open input and output image */
  60.   imgI = ImageIn (argv[1]);
  61.   imgIn = ImageGetPtr (imgI);
  62.   height = ImageGetHeight (imgI);
  63.   width = ImageGetWidth (imgI);
  64.   printf ("Input mage size is %dx%d.\n", width, height);
  65.  
  66. /* invert image */
  67.   if (invertFlag) {
  68.     for (y = 0; y < height; y++)
  69.       for (x = 0; x < width; x++)
  70.       imgIn[y][x] = 255 - imgIn[y][x];
  71.   }
  72.   imgO = ImageAlloc (height, width, 8);
  73.   imgOut = ImageGetPtr (imgO);
  74.  
  75. /* zero image borders */
  76.   yEnd = height - 1;
  77.   xEnd = width - 1;
  78.   for (y = 0; y < height; y++)
  79.     imgIn[y][0] = imgIn[y][xEnd] = OFF;
  80.   for (x = 0; x < width; x++)
  81.     imgIn[0][x] = imgIn[yEnd][x] = OFF;
  82.  
  83. /* write input to output image */
  84.   for (y = 0; y < height; y++)
  85.     for (x = 0; x < width; x++)
  86.       imgOut[y][x] = imgIn[y][x];
  87.  
  88. /* perform cellular logic iterations */
  89.   for (n = 0; n < nIter; n++) {
  90.     nChange = 0;
  91.     for (y = 1; y < yEnd; y++) {
  92.       for (x = 1; x < xEnd; x++) {
  93.         ring[0] = (imgIn[y - 1][x] > 0) ? 1 : 0;
  94.         ring[1] = (imgIn[y - 1][x + 1] > 0) ? 1 : 0;
  95.         ring[2] = (imgIn[y][x + 1] > 0) ? 1 : 0;
  96.         ring[3] = (imgIn[y + 1][x + 1] > 0) ? 1 : 0;
  97.         ring[4] = (imgIn[y + 1][x] > 0) ? 1 : 0;
  98.         ring[5] = (imgIn[y + 1][x - 1] > 0) ? 1 : 0;
  99.         ring[6] = (imgIn[y][x - 1] > 0) ? 1 : 0;
  100.         ring[7] = (imgIn[y - 1][x - 1] > 0) ? 1 : 0;
  101.         for (i = 0, fNum = 0; i < 8; i++)
  102.           fNum += ring[i];
  103.         cNum = crossnum (ring, 8);
  104.         if (connectFlag == 1 && cNum > 1);
  105.         else {
  106.           switch (opType) {
  107.           case 1:              /* dilation */
  108.             if (fNum > facThresh) {
  109.               imgOut[y][x] = ON;
  110.               nChange++;
  111.             }
  112.             break;
  113.           case 2:              /* erosion */
  114.             if (fNum < facThresh) {
  115.               imgOut[y][x] = OFF;
  116.               nChange++;
  117.             }
  118.             break;
  119.           case 3:              /* dilation-erosion */
  120.             if (fNum > facThresh) {
  121.               imgOut[y][x] = ON;
  122.               nChange++;
  123.             }
  124.             break;
  125.           case 4:              /* erosion-dilation */
  126.             if (fNum < facThresh) {
  127.               imgOut[y][x] = OFF;
  128.               nChange++;
  129.             }
  130.             break;
  131.           default:
  132.             usage (1);
  133.           }
  134.         }
  135.       }
  136.     }
  137.     printf ("iteration %d: nChange = %d\n", n, nChange);
  138.     for (y = 0; y < height; y++)
  139.       for (x = 0; x < width; x++)
  140.         imgIn[y][x] = imgOut[y][x];
  141.     if (opType == 4) {
  142.       opType = 3;
  143.       facThresh = 7 - facThresh;
  144.     }
  145.     else if (opType == 3) {
  146.       opType = 4;
  147.       facThresh = 7 - facThresh;
  148.     }
  149.   }
  150.  
  151. /* un-invert image */
  152.   if (invertFlag) {
  153.     for (y = 0; y < height; y++)
  154.       for (x = 0; x < width; x++)
  155.       imgOut[y][x] = 255 - imgOut[y][x];
  156.   }
  157.  
  158.   ImageOut (argv[2], imgO);
  159.  
  160.   return (0);
  161. }
  162.  
  163. /* CROSSNUM:    function calculates crossing number
  164.  *                    usage: crossnum (ring, nRing)
  165.  */
  166.  
  167. long
  168. crossnum (ring, nRing)
  169.      long *ring;                /* ring of neighbors around center pixel */
  170.      long nRing;                /* number of neighbors in ring */
  171.  
  172. {
  173.   long cNum;                    /* crossing number result */
  174.   long lower, upper;            /* lower and upper members of ring */
  175.   long i, m, n, k;
  176.  
  177.   k = 3;
  178.  
  179. /* calculate CNUM, first skipping corners */
  180.   for (i = 2, cNum = 0; i < nRing; i++) {
  181.     lower = (long) ring[i - 1];
  182.     if ((i % (k - 1)) == 0)
  183.       i++;                      /* skip the corner pixels */
  184.     upper = (long) ring[i];
  185.     if (upper != 0 && lower == 0)
  186.       cNum++;
  187.   }
  188.   if (ring[1] != 0 && ring[nRing - 1] == 0)
  189.     cNum++;
  190.  
  191. /* CNUM at corners */
  192.   for (n = 1; n < 4; n++) {
  193.     m = n * (k - 1);
  194.     if (ring[m] != 0) {
  195.       if (ring[m - 1] == 0 && ring[m + 1] == 0)
  196.         cNum++;
  197.     }
  198.   }
  199.   if (ring[0] != 0)
  200.     if (ring[1] == 0 && ring[nRing - 1] == 0)
  201.       cNum++;
  202.  
  203.   return (cNum);
  204. }
  205.  
  206.  
  207.  
  208. /* USAGE:       function gives instructions on usage of program
  209.  *                    usage: usage (flag)
  210.  *              When flag is 1, the long message is given, 0 gives short.
  211.  */
  212.  
  213. int
  214. usage (flag)
  215.      short flag;                /* flag =1 for long message; =0 for short message */
  216. {
  217.  
  218. /* print short usage message or long */
  219.   printf ("USAGE: cellog inimg outimg [-f FAC_THRESH] [-c CONNECTIVITY]\n");
  220.   printf ("                           [-i ITERATIONS] [-o OPERATION] [-I] [-L]\n");
  221.   if (flag == 0)
  222.     return (-1);
  223.  
  224.   printf ("\ncellog performs cellular logic of input binary image.\n\n");
  225.   printf ("ARGUMENTS:\n");
  226.   printf ("    inimg: input image filename (TIF)\n");
  227.   printf ("   outimg: output image filename (TIF)\n\n");
  228.   printf ("OPTIONS:\n");
  229.   printf ("  -f FAC_THRESH: factor number threshold, above which operation\n");
  230.   printf ("                 performed; (default = %d, range= 0-7)\n", FAC_THRESH_DFLT);
  231.   printf ("                 smaller the threshold value, the larger the effect\n");
  232.   printf ("             -c: flag to maintain connectivity; default is not set.\n");
  233.   printf ("                 NOTE: this does not guarantee retention of,\n");
  234.   printf ("                 only maintains it better than not;\n");
  235.   printf ("                 if absolute retention is required,\n");
  236.   printf ("                 use KFILL or THIN program, depending on purpose.\n");
  237.   printf ("  -i ITERATIONS: number of iterations to perform;\n");
  238.   printf ("                 (default = %d)\n", NITER_DFLT);
  239.   printf ("   -o OPERATION: for dilation(1), erosion(2), closing(3),\n");
  240.   printf ("                 or opening(4) (default = 1).\n");
  241.   printf ("                 closing operation is alternating dilation-erosion;\n");
  242.   printf ("                 opening operation is alternating erosion-dilation;\n");
  243.   printf ("                 for opening or closing, the number of iterations is\n");
  244.   printf ("                 the sum of the comprising dilation and erosion iterations.\n");
  245.   printf ("             -I: invert input image before processing\n");
  246.   printf ("             -L: print Software License for this module\n");
  247.  
  248.   return (-1);
  249. }
  250.  
  251.  
  252. /* INPUT:       function reads input parameters
  253.  *                  usage: input (argc, argv, &facThresh, &connectFlag
  254.  *                                      &nIter, &opType);
  255.  */
  256.  
  257. #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
  258.  
  259. int
  260. input (argc, argv, facThresh, connectFlag, nIter, opType, invertFlag)
  261.      int argc;
  262.      char *argv[];
  263.      long *facThresh;           /* factor number threshold */
  264.      short *connectFlag;        /* =1 to retain connectivity; 0 otherwise */
  265.      long *nIter;               /* number of iterations to perform */
  266.      long *opType;              /* operation type */
  267.      long *invertFlag;          /* invert input image before processing */
  268. {
  269.   long n;
  270.  
  271.   if (argc == 1)
  272.     USAGE_EXIT (1);
  273.   if (argc == 2)
  274.     USAGE_EXIT (0);
  275.  
  276.   *facThresh = FAC_THRESH_DFLT;
  277.   *connectFlag = 0;
  278.   *nIter = NITER_DFLT;
  279.   *opType = 1;
  280.   *invertFlag = 0;
  281.  
  282.   for (n = 3; n < argc; n++) {
  283.     if (strcmp (argv[n], "-f") == 0) {
  284.       if (++n == argc || argv[n][0] == '-')
  285.         USAGE_EXIT (0);
  286.       *facThresh = atol (argv[n]);
  287.     }
  288.     else if (strcmp (argv[n], "-c") == 0)
  289.       *connectFlag = 1;
  290.     else if (strcmp (argv[n], "-i") == 0) {
  291.       if (++n == argc || argv[n][0] == '-')
  292.         USAGE_EXIT (0);
  293.       *nIter = atol (argv[n]);
  294.     }
  295.     else if (strcmp (argv[n], "-o") == 0) {
  296.       if (++n == argc || argv[n][0] == '-')
  297.         USAGE_EXIT (0);
  298.       *opType = atol (argv[n]);
  299.     }
  300.     else if (strcmp (argv[n], "-I") == 0)
  301.       *invertFlag = 1;
  302.     else if (strcmp (argv[n], "-L") == 0) {
  303.       print_sos_lic ();
  304.       exit (0);
  305.     }
  306.     else
  307.       USAGE_EXIT (0);
  308.   }
  309.  
  310.   return (0);
  311. }
  312.